using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Comp476Project
{
    public class Player : Entity
    {
        public Camera camera;
        KeyboardState kb, prevKb;
        MouseState ms, prevMs;
        public Vector2 pausedMouse;
        public bool rootMouse;
        public int healthTimer, HTIMER;
        // maximum value for x and z to prevent character from going out of map
        public const float maxValue = 0.90f;
        public float speed;
        Primitives3D.SpherePrimitive sphere;
        public Player(Primitives3D.SpherePrimitive sphere,Matrix proj, Model mod, Vector3 pos)
            : base(sphere,proj, mod, pos)
        {
            healthTimer = 0;
            HTIMER = 1000;
            camera = new Camera();
            maxHealth = 3005;
            health = maxHealth;
            position = pos;
            kb = Keyboard.GetState();
            prevKb = kb;
            ms = Mouse.GetState();
            prevMs = ms;
            speed = 0.002f;
            pausedMouse = new Vector2(0, 0);
            rootMouse = false;
            this.sphere = sphere;
        }

        public /*override*/void update(GameTime gameTime)
        {
            refillHealth(gameTime);
            boundary();
            //handleInput(ref msVisibility);
            camera.Update(position);
            reset();
            base.update(gameTime);
        }

        public override void draw(Matrix view) 
        {

            base.draw(view);
        }

        public void handleInput(ref bool msVisibility) 
        {
            // Current States
            kb = Keyboard.GetState();
            ms = Mouse.GetState();
            // Cursor Control
            if (!rootMouse && (ms.LeftButton == ButtonState.Pressed || ms.RightButton == ButtonState.Pressed))
            {
                rootMouse = true;
                pausedMouse.X = ms.X;
                pausedMouse.Y = ms.Y;
                msVisibility = false;
            }
            if (rootMouse && ms.LeftButton != ButtonState.Pressed && ms.RightButton != ButtonState.Pressed)
            {
                Mouse.SetPosition((int)pausedMouse.X, (int)pausedMouse.Y);
                rootMouse = false;
                msVisibility = true;
            }
            // Movement
            if(kb.IsKeyDown(Keys.W))
            {
                position += direction * speed;
            }
            if (kb.IsKeyDown(Keys.S))
            {
                position -= direction * speed;
            }
            if (kb.IsKeyDown(Keys.A) && ms.RightButton != ButtonState.Pressed)
            {
                direction = Vector3.Transform(direction, Matrix.CreateRotationY(turnSpeed));
                int fix = -1;
                if (direction.X < 0)
                    fix *= -1;
                camera.sideAngle = fix * (float)(Math.Acos(Vector3.Dot(defaultDirection, -direction)));
            }
            if (kb.IsKeyDown(Keys.D) && ms.RightButton != ButtonState.Pressed)
            {
                direction = Vector3.Transform(direction, Matrix.CreateRotationY(-turnSpeed));
                int fix = -1;
                if (direction.X < 0)
                    fix *= -1;
                camera.sideAngle = fix * (float)(Math.Acos(Vector3.Dot(defaultDirection, -direction)));
            }
            if (kb.IsKeyDown(Keys.A) && ms.RightButton == ButtonState.Pressed)
            {
                position -= Vector3.Cross(direction, new Vector3(0, 1, 0)) * speed;
            }
            if (kb.IsKeyDown(Keys.D) && ms.RightButton == ButtonState.Pressed)
            {
                position += Vector3.Cross(direction, new Vector3(0, 1, 0)) * speed;
            }
            // Orientation according to camera (Right Button)
            if (ms.RightButton == ButtonState.Pressed)
            {
                direction = new Vector3(position.X - camera.pos.X, 0, position.Z - camera.pos.Z);
                direction.Normalize();
                direction = Vector3.Transform(direction, Matrix.CreateRotationY((turnSpeed / 2) * (prevMs.X - ms.X)));
                int fix = -1;
                if (direction.X < 0)
                    fix *= -1;
                camera.sideAngle = fix * (float)(Math.Acos(Vector3.Dot(defaultDirection, -direction)));
            }
            // Previous States
            prevKb = kb;
            prevMs = ms;

        }// end handling

        public void mapYPosition(float[][] map,int size) 
        {
            // Bachir's Implementation of Y Interpolation
            //float xVal = ((position.X + 1) * size) / 2;
            //float zVal = ((position.Z + 1) * size ) / 2;
            //int xInt = (int)Math.Round(xVal);
            //int zInt = (int)Math.Round(zVal);
            //Vector2 pos = new Vector2(xVal, zVal);
            //Vector2 gPos0 = new Vector2(xInt, zInt);
            //Vector2 gPos1 = new Vector2(xInt + 1, zInt);
            //Vector2 gPos2 = new Vector2(xInt, zInt + 1);
            //Vector2 gPos3 = new Vector2(xInt + 1, zInt + 1);
            //float d = Vector2.Distance(gPos0, gPos3);
            //float dist0 = Vector2.Distance(pos, gPos0) / d;
            //float dist1 = Vector2.Distance(pos, gPos1) / d;
            //float dist2 = Vector2.Distance(pos, gPos2) / d;
            //float dist3 = Vector2.Distance(pos, gPos3) / d;
            //position.Y = (dist0 * map[(int)gPos0.X][(int)gPos0.Y] + dist1 * map[(int)gPos1.X][(int)gPos1.Y] + dist2 * map[(int)gPos2.X][(int)gPos2.Y] + dist3 * map[(int)gPos3.X][(int)gPos3.Y]) / (dist0 + dist1 + dist2 + dist3);

            // Mike's Implementation of Y Interpolation
            int xVal = (int)Math.Round(((position.X - (-1)) * size) / 2);
            int zVal = (int)Math.Round(((position.Z - (-1)) * size) / 2);
            if (map[xVal][zVal] != 0)
            {
                float diff = Math.Abs(position.Y - map[xVal][zVal]);

                if (diff > 0.01)
                {
                    position.Y = ((map[xVal][zVal] - position.Y) / 2) + position.Y;

                }
                else
                    position.Y = map[xVal][zVal];
            }
        }//end of function

        public void boundary() 
        {
            if(position.X>maxValue)
            {
                position.X = maxValue;
            }
            if (position.X < -maxValue) 
            {
                position.X = -maxValue;
            }

            if (position.Z > maxValue) 
            {
                position.Z = maxValue;
            }
            if (position.Z < -maxValue) 
            {
                position.Z = -maxValue;
            }
        }//end of boundary

        public void refillHealth(GameTime gameTime) 
        {
            Vector3 hq= new Vector3(0.002f, 0.04f, -0.781f);
            float dist= (position-hq).Length();
            if (dist < 0.15 && health < maxHealth)
            {
                healthTimer += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
                if (healthTimer >= HTIMER) 
                {
                    health += 10;
                }
            }
        }// end of refill 

        public void reset() 
        {
            if (health <= 0) 
            {
                position = new Vector3(0.001f, 0f, -0.698f);
                health = maxHealth / 4;
            }
        }
    }
}
